package tk3.project.uploadservice;

import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Vector;

import android.hardware.Camera.Size;




public class Client extends Thread{
	private boolean running=true;
	private String ip_adress="";
	private int port=80;
	private Vector<Picture> pics;
	private ObjectInputStream inFromServer;
	private ObjectOutputStream outToServer;
	private String storePath="";
	private Vector<Picture> receivedPictures;

	/**
	 * Creates a new up/download  client
	 * @param ip_adress - ip of the server
	 * @param port - server port
	 * @param storePath - where to store the downloaded pictures
	 */
	public Client(String ip_adress,int port, String storePath){
		this.ip_adress=ip_adress;
		this.port=port;
		pics=new Vector<Picture>();
		this.storePath=storePath;
		receivedPictures=new Vector<Picture>();
	}

	
	public void run(){
		System.out.println("Android Client up and running");
		while(running==true){
			if(!hasPictures()){
				try {
					sleep(2000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					//e.printStackTrace();
				}
			}
			else{
				System.out.println("Client Submits Pictures");
				submitPictures();
			}
		}
	}
	
	/**
	 * Add picutes to the submit queue
	 * @param picsToShare - Pictures to be uploaded
	 */
	public synchronized void sendPictures(Vector<Picture> picsToShare){
		pics.addAll(picsToShare);	
	}
	/**
	 * Add picutes to the submit queue
	 * @param picsToShare - Pictures to be uploaded
	 */
	public synchronized void sendPicture(Picture picToShare){
		if(!isDownloadedPicture(picToShare)){
			System.out.println("Client added pic: " + picToShare.getPath().getPath());
			pics.add(picToShare);
		}
		
	}
	/**
	 * Pull pictures from the server with the current gps position
	 * @param lat - my current latitude
	 * @param lon - my current londitude
	 * @param radius - the radius around me from which positions I want to receive new picures
	 */
	public synchronized void getPictures(double lat, double lon, int radius){
		send2(new Message(radius, lon,lat,latestReceivedPicture()));
	}
	/**
	 * Pull pictures from the server with a stream name
	 * @param stream - the stream name
	 * @param password - The password for the stream
	 */
	public synchronized void getPictures(String stream, String password){
		send2(new Message( stream, password,latestReceivedPicture()));
	}
	
	/**
	 * Sending queued pictures
	 * @return
	 */
	private synchronized boolean submitPictures(){
		if(send2(new Message(loadPictures()))){
			pics.removeAllElements();
			return true;
		}
		return false;
	}
	/**
	 * Picutes are stored on the HDD for sending, the picture is loaded into an array of the 
	 * picture class and the complete object is send over the network
	 * @return The Picture objects with pictures loaded
	 */
	private synchronized Vector<Picture> loadPictures(){
		for(int i=0;i<pics.size();i++){
			pics.get(i).loadPicture();
		}
		return pics;
	}

	/**
	 * The actual sending of the picutes over the network
	 * @param m - Message encapsulation of the pictures
	 * @return if the server has ACKed the received message
	 */
	private boolean send2(Message m){
		boolean ret=false;
		try {	
			Socket clientSocket = new Socket(ip_adress, port);
			clientSocket.setSoTimeout(20000);
			inFromServer = new ObjectInputStream(clientSocket.getInputStream());
			outToServer = new ObjectOutputStream(clientSocket.getOutputStream());
			if(m.getType()==1)System.out.println("Client submits "+m.getPictures().size()+" Pictures");
			outToServer.writeObject(m);
			outToServer.flush();

			Message msg=null;
			try {
				msg = (Message)inFromServer.readObject();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			if(msg.getType()==1){
				  System.out.println("Received "+msg.getPictures().size()+" Pictures");
				  for(Picture pic:msg.getPictures()){
					  if(pic.isFileExisting(storePath))
						  pic.unloadExistingPicture(storePath);
					  else
						  pic.unloadNewPicture(storePath);
					  addReceivedPicture(pic);
				  }
				  System.out.println("Sending Ack");
				  outToServer.writeObject(new Message(msg.getPictures().size()));
				  outToServer.flush();
				  ret=true;
			}
			else if(msg.getType()==2){
				if(m.getPictures().size()==msg.getAcks()){
					  System.out.println("All files submitted correctly");
					  ret=true;
				  }
				  else{
					  System.out.println("Error during picture submission");
				  }
			}
			else{
				System.out.println("UUps something went wrong...client received a message type no able to handle");
			}
			  
			clientSocket.close();

		} 
		catch (UnknownHostException e) {
			e.printStackTrace();
		} 
		catch (IOException e) {
			e.printStackTrace();
		}
		return ret;
	}
	
	/**
	 * Look before sending of the pictures if this file has just been downloaded from the server
	 * @param p - The picture to check
	 * @return true if the picture has been downloaded in this session
	 */
	private synchronized boolean isDownloadedPicture(Picture p){
		for(Picture compare:receivedPictures){
			if(compare.getPath().equals(p.getPath()))
				return true;
		}
		return false;
	}
	/**
	 * Add picture to the downloaded picture list
	 * @param p - a new picture
	 */
	private synchronized void addReceivedPicture(Picture p){
		receivedPictures.add(p);
	}
	/**
	 * The date of the picture which has been downloaded last.
	 * @return
	 */
	private synchronized Date latestReceivedPicture(){
		Date d;
		if(receivedPictures==null||receivedPictures.isEmpty()){
				return new Date(0);
		}
		else{
			d=receivedPictures.get(0).getDate();
			for(Picture p:receivedPictures)
				if(d.before(p.getDate()))
					d=p.getDate();
			
		}
		return d;
	}

	
	/**
	 * 
	 * @return true if pictures are in sending queue
	 */
	private synchronized boolean hasPictures(){
		return !pics.isEmpty();
	}
	
	/**
	 * finish the thread
	 */
	public void stopClient(){
		running = false;
	}
}
